/**
 ******************************************************************************
 * @file	bl_sleep.c
 * @brief	LCD背光调节


 * 5秒没有输入调低屏幕亮度，10 秒没有输入则关闭屏幕，
 * 控制台输入
 * ./bl_sleep.elf -t 10 -D /dev/input/event0


- 2016-9-30,MenglongWu,MenglongWoo@aliyun.com
 	- brief

*/


#include <linux/input.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>
#include "key-name.h"

#include "printl.h"
#include "proginfo.h"
#include "autoconfig.h"
/*
 * 不要将MIN_LEVEL调成0，否则及时当背光打开时用户也看不到屏幕内容，
 * 误以为设备损坏，保证最小亮度也是能看到屏幕内容的
*/
#define MIN_LEVEL       (10)				// 可调节最暗亮度
#define AFTER_N_SEC	(5)				// 最后n秒调暗背光
#define LOW_POWER_LEVEL (30)


char *device   = "/dev/input/event0";			// 默认设备
char *bl_dev = "/sys/class/backlight/mxs-bl/";		// LCD背光电源
int timeout   = 30;					// 无操作超时
int level     = 80;					// 关闭前LCD背光亮度


char strout[128];
static void print_usage(const char *prog)
{
	printf("Usage: %s [-DsbdlHOLC3]\n", prog);
	puts("  -D --device   device to use (default /dev/input/event0)\n"
	     "  -p --power    backlight power (default /sys/class/backlight/mxs-bl/)\n"
	     "  -t --timeout  no input event timeout (30 sec)\n");
	exit(1);
}


static void parse_opts(int argc, char *argv[])
{
	while (1) {
		static const struct option lopts[] = {
			{ "device",  1, 0, 'D' },
			{ "timeout", 1, 0, 't' },
			{ "bl_dev", 1, 0, 'p' },
			{ NULL, 0, 0, 0 },
		};
		int c;

		c = getopt_long(argc, argv, "D:p:t:", lopts, NULL);

		if (c == -1) {
			break;
		}

		switch (c) {
		case 'D':
			device = optarg;
			break;
		case 'p':
			bl_dev = optarg;
			break;
		case 't':
			timeout = atoi(optarg);
			if (timeout < 10) {
				timeout = 10;
			} else if (timeout > 5 * 60) {
				timeout = 5 * 60;
			}
			break;
		default:
			print_usage(argv[0]);
			break;
		}
	}
}


static inline void full_bl_level()
{
	snprintf(strout, 128, "echo 80 > " "%s" "/brightness", bl_dev);
	system(strout);
}




#if defined(CONFIG_BL_LOW_POWER_LEVEL)
static inline void save_bl_level()
{
	FILE *fp;
	char strout[128];

	snprintf(strout, 128, "cat " "%s" "/brightness", bl_dev);
	fp = popen((char *)strout, "r");
	if (fp == NULL) {
		return ;
	}

	fscanf(fp, "%d", &level);
	pclose(fp);

	if (level < MIN_LEVEL) {
		level = 100;
	}
}
static inline void restore_bl_level()
{
	snprintf(strout, 128, "echo %d > " "%s" "/brightness", level, bl_dev);
	system(strout);
}

/**
 * @brief	调低背光亮度
 * @remarks	如果但当前背光亮度小于低低功耗背光(LOW_POWER_LEVEL)则不调节
 */

static inline void low_bl_level()
{
	FILE *fp;
	int old_level;

	snprintf(strout, 128, "cat " "%s" "/brightness", bl_dev);
	fp = popen((char *)strout, "r");
	if (fp == NULL) {
		return ;
	}

	fscanf(fp, "%d", &old_level);
	pclose(fp);
	if (old_level < LOW_POWER_LEVEL) {
		return ;
	}


	snprintf(strout, 128, "echo 30 > ""%s""/brightness", bl_dev);
	system(strout);
}



#else
static inline void save_bl_level() {}
static inline void restore_bl_level() {}
static inline void low_bl_level() {}
#endif


static inline void off_bl_power()
{
	snprintf(strout, 128, "echo 1 >" "%s" "/bl_power", bl_dev);
	system(strout);
}

static inline void on_bl_power()
{
	snprintf(strout, 128, "echo 0 > ""%s""/bl_power", bl_dev);
	system(strout);
}


int fd;


// 自动检测 /dev/input 输入，如果30s内没有任何输入关闭LCD背光
// 检测间隔为1s
void *ThreadBlacklight(void *arg)
{
	int touch_down = 0;
	struct input_event touch_key;

	fd = open(device, O_RDONLY);
	if (fd < 0) {
		printf("fail open device %s\n", device);
		return 0;
	}


	int len;
	int loop;
	char *keystatus = "unknow";
	while(1) {
		len = read(fd, &touch_key, sizeof(touch_key));
		if (len != -1 && touch_key.type == EV_KEY) {
			touch_down = 1;
			switch(touch_key.value) {
			case 1:
				keystatus = "down";
				break;
			case 2:
				keystatus = "press";
				break;
			case 0:
				keystatus = "up";
				break;
			default:
				keystatus = "unknow";
				PRINTE("code %x %x %x\n", touch_key.code, touch_key.value, touch_key.type);
				break;
			}
			// dbg("code %x %x %x\n", touch_key.code, touch_key.value, touch_key.type);

			printf("%s\t%x\t%s\n", keystatus, touch_key.code,  disp_keyname(touch_key.code));
		}


	}
	close(fd);
}

int main(int argc, char *argv[])
{
	parse_opts(argc, argv);

	ThreadBlacklight(NULL);

}

MODULE_PROJECT(PRJ_NAME);
#if  defined(PRJ_VERSION) && defined(PRJ_PATCHLEVEL) && defined(PRJ_SUBLEVEL)
	MODULE_VERSION(PRJ_VERSION "." PRJ_PATCHLEVEL "." PRJ_SUBLEVEL);
#endif
MODULE_BUILD(__DATE__ " " __TIME__);
PROG_GITSHA1(__GIT_SHA1__);